﻿using System;
using System.Net;
using System.ServiceModel.Description;

namespace NerdWare.Crm2011VsTools.Core.Crm
{
    public class CrmApplicationDescriptor
    {
        /// <summary>
        /// CRM 2011:
        ///     - OnPremise (Windows Authentication)
        /// CRM 4.0:
        ///     - OnPremise (Windows Authentication)
        /// </summary>
        /// <param name="crmVersion"></param>
        /// <param name="serverName"></param>
        /// <param name="serverPort"></param>
        public CrmApplicationDescriptor(CrmVersionEnum crmVersion, string serverName, int serverPort) : this(crmVersion, null, serverName, serverPort, true, null, null, null) { }

        /// <summary>
        /// CRM 2011:
        ///     - OnPremise (Username Password)
        /// CRM 4.0:
        ///     - OnPremise (Username Password)
        /// </summary>
        /// <param name="crmVersion"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        public CrmApplicationDescriptor(CrmVersionEnum crmVersion, string username, string password) : this(crmVersion, null, null, 443, false, username, password, null) { }

        /// <summary>
        /// CRM 2011:
        ///     - Online with LiveID
        /// </summary>
        /// <param name="discoveryUrl"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        public CrmApplicationDescriptor(CrmVersionEnum crmVersion, string discoveryUrl, string username, string password) : this(crmVersion, discoveryUrl, null, 443, false, username, password, null) { }

        private CrmApplicationDescriptor(CrmVersionEnum crmVersion, string discoveryUrl, string serverName, int serverPort,
                                            bool defaultCredentials, string username, string password,
                                            string domain)
        {
            _crmVersion = crmVersion;
            _discoveryUrl = discoveryUrl;
            _serverName = serverName;
            _serverPort = serverPort;
            _defaultCredentials = defaultCredentials;
            _username = username;
            _password = password;
            _domain = domain;
            _scheme = serverPort == 443 ? Scheme.Https : Scheme.Http;
        }

        private readonly CrmVersionEnum _crmVersion;
        private readonly string _discoveryUrl;
        private readonly string _scheme;
        private readonly string _serverName;
        private readonly string _username;
        private readonly string _password;
        private readonly string _domain;
        private readonly int _serverPort;
        private readonly bool _defaultCredentials;

        private ClientCredentials _clientCredentials;

        public ClientCredentials GetClientCredentials()
        {
            return _clientCredentials ?? (_clientCredentials = getClientCredentials());
        }

        private ICredentials _credentials;

        public ICredentials GetCredentials()
        {
            return _credentials ?? (_credentials = getCredentials());
        }

        private Uri _discoveryUri;

        public Uri GetDiscoveryUri()
        {
            return _discoveryUri ?? (_discoveryUri = getDiscoveryUri());
        }

        public string GetDiscoveryUrl()
        {
            return GetDiscoveryUri().ToString();
        }

        private ClientCredentials getClientCredentials()
        {
            if (_crmVersion != CrmVersionEnum.Crm2011)
                throw new NotSupportedException("Only supported in CRM 2011");

            ClientCredentials clientCredentials = new ClientCredentials();

            if (string.IsNullOrEmpty(_discoveryUrl))
            {
                clientCredentials.Windows.ClientCredential = _defaultCredentials
                                                 ? CredentialCache.DefaultNetworkCredentials
                                                 : new NetworkCredential(_username, _password, _domain);
            }
            else
            {
                clientCredentials.UserName.UserName = _username;
                clientCredentials.UserName.Password = _password;
            }

            return clientCredentials;
        }

        private ICredentials getCredentials()
        {
            if (_crmVersion != CrmVersionEnum.Crm40)
                throw new NotSupportedException("Only supported in CRM 4.0");

            return this._defaultCredentials ?
                      CredentialCache.DefaultCredentials :
                      new NetworkCredential(_username, _password, _domain);
        }

        private Uri getDiscoveryUri()
        {
            UriBuilder uriBuilder;

            if (!string.IsNullOrEmpty(_discoveryUrl))
            {
                uriBuilder = new UriBuilder(_discoveryUrl);
            }
            else
            {
                switch (_crmVersion)
                {
                    case CrmVersionEnum.Crm2011:
                        uriBuilder = new UriBuilder(string.Format("{0}://{1}:{2}", _scheme, _serverName, _serverPort)) { Path = "XRMServices/2011/Discovery.svc" };
                        break;
                    case CrmVersionEnum.Crm40:
                        uriBuilder = new UriBuilder(string.Format("{0}://{1}:{2}", _scheme, _serverName, _serverPort)) { Path = "MSCRMServices/2007/AD/CrmDiscoveryService.asmx" };
                        break;
                    default:
                        uriBuilder = new UriBuilder();
                        break;
                }
            }

            return uriBuilder.Uri;
        }
    }
}
